#pragma once
#include <iostream>
#include <string>
#include <sys/select.h>
#include <memory>
#include "log.hpp"
#include "Socket.hpp"
#include <poll.h>
#include "Epollr.hpp"
const static int gdefaultport = 8888;
const static int gbacklog = 32;
using namespace socketmodule;
using namespace EpollerModule;
std::string EventToString(uint32_t events)
{
    std::string info;
    if (events & EPOLLIN)
        info += "EPOLLIN ";
    if (events & EPOLLOUT)
        info += "EPOLLOUT ";
    if (events & EPOLLET)
        info += "EPOLLET";

    return info;
}
class Epoll_sever
{
    static const int gmaxevents = 64;

public:
    Epoll_sever(int port = gdefaultport) : _port(port), _listensock(new TcpSocket()), _isrunning(false), _epoller(new Epoller())
    {
    }
    // bool Initserver()
    // {
    //     _listensock->BuildListenSocketMethod(_port, gbacklog);
    //     lg.massage(Info, "listen sock success lisensock is:%d\n", _listensock->GetSockFd());
    //     _epoller->InitEpoller();
    //     lg.massage(Info, "init epoller success\n");
    //     _epoller->AddEvent(_listensock->GetSockFd(), EPOLLIN);
    //     return true;
    // }
    bool Initserver()
    {
        // 1. 创建listensock
        _listensock->BuildListenSocketMethod((uint16_t)_port, gbacklog);
        lg.massage(Info, "init socket success, listensock is : %d\n", _listensock->GetSockFd());
        // 2. 创建epoll模型
        _epoller->InitEpoller();
        lg.massage(Info, "init epoller success\n");
        // 3. 将listensock添加到epoll中
        _epoller->AddEvent(_listensock->GetSockFd(), EPOLLIN);
        return true;
    }
     bool Accepter(std::string *peerip, uint16_t *peerport)
    {
        // 监听事件就绪
       int sock = _listensock->AAcceptConnection(peerip, peerport);
        if (sock < 0)
        {
            lg.massage(Warning, "accept error");
            return false;
        }
        // 获取链接成功
        _epoller->AddEvent(sock, EPOLLIN);
        return true;
    }
    // bool Accepter(string *clientip, uint16_t *port)
    // {
    //     Socket *sock = _listensock->AcceptConnection(clientip, port);
    //     int sockfd = sock->GetSockFd();
    //     if (sockfd < 0)
    //     {
    //         lg.massage(Warning, "accpet sock error");
    //         return false;
    //     }
    //     _epoller->AddEvent(sockfd, EPOLLIN);
    //     return true;
    // }
    // int Recver(int sockfd, string *out)
    // {
    //     char buffer[1024];
    //     int n = recv(sockfd, buffer, sizeof(buffer), 0);
    //     if (n > 0)
    //     {
    //         buffer[n] = 0;
    //         *out = buffer;
    //     }
    //     return n;
    // }
     int Recver(int sockfd, std::string *out)
    {
        // 真实情况是：每一个sockfd都要有一个自己的输入和输出缓冲区！！！！！
        // 其实是要对sockfd进行封装的，要不然无法把底层fd和上层关联起来！
        char buffer[1024];
        int n = ::recv(sockfd, buffer, sizeof(buffer), 0); // Bug???
        if (n > 0)
        {
            buffer[n] = 0;
            *out = buffer;
        }
        return n;
    }
    void HandlerEvent(int n)
    {
        lg.massage(Debug, "%d 个 events 已经就绪了\n", n);
        for (int i = 0; i < n; i++)
        {
            lg.massage(Debug, "ready fd: %d, Event is: %s\n",
                          _revs[i].data.fd, EventToString(_revs[i].events).c_str());

            int sockfd = _revs[i].data.fd;
            uint32_t events = _revs[i].events;
            if (events & EPOLLIN)
            {
                // 读事件分两种：1. listen 2. normal sockfd
                if (sockfd == _listensock->GetSockFd())
                {
                    std::string clientip;
                    uint16_t clientport;
                    if (!Accepter(&clientip, &clientport))
                        continue;
                    lg.massage(Info, "accept client success, client[%s:%d]\n",
                                  clientip.c_str(), clientport);
                }
                else
                {
                    std::string message;
                    int n = Recver(sockfd, &message);
                    if (n > 0)
                    {
                        std::cout << "client# " << message << std::endl;
                        message.resize(message.size()-strlen("\r\n"));
                        // 直接写 -- TODO
                        std::string echo_message = "echo message: " + message + "\r\n";
                        send(sockfd, echo_message.c_str(), echo_message.size(), 0);
                    }
                    else
                    {
                        if (n == 0)
                        {
                            lg.massage(Info, "client %d close\n", sockfd);
                        }
                        else
                        {
                            lg.massage(Info, "client recv %d error\n", sockfd);
                        }
                        // epoll移除一个fd，这个fd必须是合法的fd，才能被正确移除
                        _epoller->DelEvent(sockfd);
                        ::close(sockfd);
                    }
                }
            }
        }
    }
    // void Loop()
    // {
    //     _isrunning = true;
    //     while (_isrunning)
    //     {
    //         _epoller->DebugFdList();
    //         int timeout = -1;
    //         int n = _epoller->Wait(_revs, gmaxevents, timeout);
    //         switch (n)
    //         {
    //         case 0:
    //             lg.massage(Debug, "timeout...\n");
    //             break;
    //         case -1:
    //             lg.massage(Error, "epoll wait failed!\n");
    //             break;
    //         default:
    //             // 事件就绪了
    //             lg.massage(Info, "event happend ... \n");
    //             HandlerEvent(n);
    //             break;
    //         }
    //     }
    //     _isrunning = false;
    // }
    void Loop()
    {
        _isrunning = true;
        while (_isrunning)
        {
            _epoller->DebugFdList();
            int timeout = -1;                                   // 1S
            int n = _epoller->Wait(_revs, gmaxevents, timeout); // 方便测试，阻塞方案
            switch (n)
            {
            case 0:
                lg.massage(Debug, "timeout...\n");
                break;
            case -1:
                lg.massage(Error, "epoll wait failed!\n");
                break;
            default:
                // 事件就绪了
                lg.massage(Info, "event happend ... \n");
                HandlerEvent(n);
                break;
            }
        }
        _isrunning = false;
    }
    ~Epoll_sever()
    {
    }

private:
    std::unique_ptr<Socket> _listensock;
    std::unique_ptr<Epoller> _epoller;
    int _port;
    bool _isrunning;
    struct epoll_event _revs[gmaxevents];
};